package com.project.common.caching;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.project.common.caching.provider.CacheProvider;
import com.project.common.data.Persistence;
import com.project.common.exception.BusinessException;
import com.project.common.exception.ErrorCodes;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public abstract class HashCacheRepository<K extends Serializable, P extends Persistence<K>>
        implements CacheRepository<K, P> {
    private static final List<String> PUBLISH_KEY = new ArrayList<String>() {
        {
            add("amount_day");
            add("api_plugins");
            add("apis");
            add("app_grant");
            add("app_limit");
            add("apps");
            add("cluster");
            add("platform");
            add("plugin_params");
            add("plugins");
            add("regulation_api");
        }
    };

    private final ObjectMapper objectMapper;
    private final CacheProvider cacheProvider;

    public HashCacheRepository(CacheProvider cacheProvider, ObjectMapper objectMapper) {
        this.cacheProvider = cacheProvider;
        this.objectMapper = objectMapper;
    }

    /**
     * 缓存初始化接口
     */
    public void initialize() {

    }

    /**
     * 获取缓存
     */
    public P get(K key) {
        CacheOption cacheOption = this.getCacheOption();
        if (!cacheOption.enabled()) {
            return null;
        }
        String value = cacheProvider.forHash().get(cacheOption.hashKey(), String.valueOf(key));
        return deserialize(value);
    }

    /**
     * 设置缓存
     *
     * @param persistence
     */
    public void set(P persistence) {
        CacheOption cacheOption = this.getCacheOption();
        if (!cacheOption.enabled()) {
            return;
        }

        message(persistence, cacheOption);
    }

    /**
     * 设置缓存
     *
     * @param persistences
     */
    public void set(Collection<P> persistences) {
        CacheOption cacheOption = this.getCacheOption();
        if (!cacheOption.enabled()) {
            return;
        }
        persistences.forEach(persistence -> message(persistence, cacheOption));
    }

    private void message(P persistence, CacheOption cacheOption) {
        String message = serialize(persistence);
        if (PUBLISH_KEY.contains(cacheOption.hashKey())) {
            cacheProvider.publish(cacheOption.hashKey(), message);
        } else {
            cacheProvider.forHash().put(cacheOption.hashKey(),
                    String.valueOf(persistence.getKey()), message);
        }
    }

    /**
     * 删除缓存
     *
     * @param key
     */
    public void delete(K key) {
        CacheOption cacheOption = this.getCacheOption();
        if (!cacheOption.enabled()) {
            return;
        }

        if (PUBLISH_KEY.contains(cacheOption.hashKey())) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", key);
            map.put("operation", 2); // 1-新增，2-删除，3-修改
            cacheProvider.publish(cacheOption.hashKey(), serialize(map));
        } else {
            cacheProvider.forHash().delete(cacheOption.hashKey(), String.valueOf(key));
        }
    }

    /**
     * 获取所有缓存
     *
     * @return
     */
    public List<P> all() {
        CacheOption cacheOption = this.getCacheOption();
        if (!cacheOption.enabled()) {
            return null;
        }
        List<String> values = cacheProvider.forHash().getAll(cacheOption.hashKey());
        if (values == null || values.isEmpty()) {
            return null;
        }
        return values.stream().map(this::deserialize).collect(Collectors.toList());
    }

    protected String serialize(Object value) {
        if (value == null) {
            return null;
        }
        try {
            if (camelToLowerCase()) {
                objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
            }
            return objectMapper.writeValueAsString(value);
        } catch (JsonProcessingException e) {
            throw new BusinessException(
                    ErrorCodes.Common.ERROR_CACHE_OPERATION.errorCode("序列化缓存失败!"));
        }
    }

    protected P deserialize(String value) {
        if (StringUtils.isBlank(value)) {
            return null;
        }
        try {
            if (camelToLowerCase()) {
                objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
            }
            return objectMapper.readValue(value, getCacheClass());
        } catch (IOException e) {
            throw new BusinessException(
                    ErrorCodes.Common.ERROR_CACHE_OPERATION.errorCode("反序列化缓存失败!"));
        }
    }

    /**
     * 获取Hash缓存选项
     *
     * @return
     */
    protected abstract CacheOption getCacheOption();

    /**
     * 获取缓存的Java类型
     *
     * @return
     */
    protected abstract Class<P> getCacheClass();

    protected abstract Boolean camelToLowerCase();
}
